summaryrefslogblamecommitdiff
path: root/apps/mobile/app/task/[id].tsx
blob: 121063afa77e373f4659ecaf57f33bd8f338e32e (plain) (tree)


































































































































































































































































                                                                                                  
import React from 'react';
import {
  View,
  Text,
  StyleSheet,
  ScrollView,
  useColorScheme,
  ActivityIndicator,
} from 'react-native';
import { useLocalSearchParams, Stack } from 'expo-router';
import { Colors } from '../../constants/Colors';
import { useTask } from '../../hooks/useTasks';
import { TaskStatusBadge } from '../../components/TaskStatusBadge';
import { EmptyState } from '../../components/EmptyState';

export default function TaskDetailScreen() {
  const colorScheme = useColorScheme() ?? 'light';
  const colors = Colors[colorScheme];
  const { id } = useLocalSearchParams<{ id: string }>();

  const { data: task, isLoading, isError } = useTask(id);

  if (isLoading) {
    return (
      <>
        <Stack.Screen options={{ title: 'Loading...' }} />
        <View style={[styles.container, styles.centered, { backgroundColor: colors.background }]}>
          <ActivityIndicator size="large" color={colors.tint} />
        </View>
      </>
    );
  }

  if (isError || !task) {
    return (
      <>
        <Stack.Screen options={{ title: 'Error' }} />
        <View style={[styles.container, { backgroundColor: colors.background }]}>
          <EmptyState
            icon="alert-circle-outline"
            title="Failed to load task"
            message="The task could not be found or an error occurred"
          />
        </View>
      </>
    );
  }

  return (
    <>
      <Stack.Screen options={{ title: task.name }} />
      <ScrollView
        style={[styles.container, { backgroundColor: colors.background }]}
        contentContainerStyle={styles.content}
      >
        {/* Header */}
        <View style={[styles.header, { backgroundColor: colors.card }]}>
          <View style={styles.headerTop}>
            <TaskStatusBadge status={task.status} showLabel size="large" />
          </View>
          <Text style={[styles.taskName, { color: colors.text }]}>
            {task.name}
          </Text>
          {task.description && (
            <Text style={[styles.description, { color: colors.secondaryText }]}>
              {task.description}
            </Text>
          )}
        </View>

        {/* Progress Summary */}
        {task.progressSummary && (
          <View style={[styles.section, { backgroundColor: colors.card }]}>
            <Text style={[styles.sectionTitle, { color: colors.text }]}>
              Progress
            </Text>
            <Text style={[styles.progressText, { color: colors.secondaryText }]}>
              {task.progressSummary}
            </Text>
          </View>
        )}

        {/* Task Info */}
        <View style={[styles.section, { backgroundColor: colors.card }]}>
          <Text style={[styles.sectionTitle, { color: colors.text }]}>
            Details
          </Text>

          <View style={styles.infoRow}>
            <Text style={[styles.infoLabel, { color: colors.secondaryText }]}>
              Created
            </Text>
            <Text style={[styles.infoValue, { color: colors.text }]}>
              {new Date(task.createdAt).toLocaleString()}
            </Text>
          </View>

          {task.startedAt && (
            <View style={styles.infoRow}>
              <Text style={[styles.infoLabel, { color: colors.secondaryText }]}>
                Started
              </Text>
              <Text style={[styles.infoValue, { color: colors.text }]}>
                {new Date(task.startedAt).toLocaleString()}
              </Text>
            </View>
          )}

          {task.completedAt && (
            <View style={styles.infoRow}>
              <Text style={[styles.infoLabel, { color: colors.secondaryText }]}>
                Completed
              </Text>
              <Text style={[styles.infoValue, { color: colors.text }]}>
                {new Date(task.completedAt).toLocaleString()}
              </Text>
            </View>
          )}

          {task.repositoryUrl && (
            <View style={styles.infoRow}>
              <Text style={[styles.infoLabel, { color: colors.secondaryText }]}>
                Repository
              </Text>
              <Text
                style={[styles.infoValue, { color: colors.tint }]}
                numberOfLines={1}
              >
                {task.repositoryUrl}
              </Text>
            </View>
          )}
        </View>

        {/* Subtasks */}
        {task.subtasks && task.subtasks.length > 0 && (
          <View style={[styles.section, { backgroundColor: colors.card }]}>
            <Text style={[styles.sectionTitle, { color: colors.text }]}>
              Subtasks ({task.subtasks.length})
            </Text>
            {task.subtasks.map((subtask) => (
              <View key={subtask.id} style={styles.subtaskRow}>
                <TaskStatusBadge status={subtask.status} size="small" />
                <Text
                  style={[styles.subtaskName, { color: colors.text }]}
                  numberOfLines={1}
                >
                  {subtask.name}
                </Text>
              </View>
            ))}
          </View>
        )}

        {/* Error message */}
        {task.errorMessage && (
          <View style={[styles.section, styles.errorSection]}>
            <Text style={[styles.sectionTitle, { color: '#991b1b' }]}>
              Error
            </Text>
            <Text style={styles.errorText}>{task.errorMessage}</Text>
          </View>
        )}

        {/* Placeholder for future features */}
        <View style={styles.placeholder}>
          <Text style={[styles.placeholderText, { color: colors.secondaryText }]}>
            Task output and controls will be added here
          </Text>
        </View>
      </ScrollView>
    </>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  centered: {
    justifyContent: 'center',
    alignItems: 'center',
  },
  content: {
    padding: 16,
    gap: 16,
  },
  header: {
    padding: 16,
    borderRadius: 12,
    gap: 8,
  },
  headerTop: {
    flexDirection: 'row',
    justifyContent: 'flex-start',
  },
  taskName: {
    fontSize: 20,
    fontWeight: '700',
  },
  description: {
    fontSize: 14,
    lineHeight: 20,
  },
  section: {
    padding: 16,
    borderRadius: 12,
    gap: 12,
  },
  sectionTitle: {
    fontSize: 16,
    fontWeight: '600',
  },
  progressText: {
    fontSize: 14,
    lineHeight: 20,
  },
  infoRow: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
  },
  infoLabel: {
    fontSize: 14,
  },
  infoValue: {
    fontSize: 14,
    fontWeight: '500',
    flex: 1,
    textAlign: 'right',
    marginLeft: 16,
  },
  subtaskRow: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 8,
    paddingVertical: 4,
  },
  subtaskName: {
    fontSize: 14,
    flex: 1,
  },
  errorSection: {
    backgroundColor: '#fee2e2',
  },
  errorText: {
    fontSize: 14,
    color: '#991b1b',
    lineHeight: 20,
  },
  placeholder: {
    padding: 32,
    alignItems: 'center',
  },
  placeholderText: {
    fontSize: 14,
    textAlign: 'center',
  },
});